package com.simen.downloader;

import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by zhangming on 16/4/11.
 */
final class DownloadEngine {
    final DownloadConfiguration configuration;

    private Executor workExecutor;
    private Executor fileExecutor;
    private final Map<String, ReentrantLock> uriLocks = new WeakHashMap<String, ReentrantLock>();

    private final AtomicBoolean paused = new AtomicBoolean(false);
    private final Object pauseLock = new Object();

    public DownloadEngine(DownloadConfiguration configuration) {
        this.configuration = configuration;
        initExecutorsIfNeed();
    }

    private void initExecutorsIfNeed() {
        if (workExecutor == null || ((ExecutorService) workExecutor).isShutdown()) {
            workExecutor = DefaultConfigurationFactory
                    .createExecutor(configuration.threadPoolSize, Thread.NORM_PRIORITY - 2);
        }

        if (fileExecutor == null || ((ExecutorService) fileExecutor).isShutdown()) {
            fileExecutor = DefaultConfigurationFactory
                    .createExecutor(configuration.threadPoolSize, Thread.NORM_PRIORITY - 2);
        }
    }

    /**
     * Pauses engine. All new "load&display" tasks won't be executed until ImageLoader is {@link #resume() resumed}.<br
     * /> Already running tasks are not paused.
     */
    void pause() {
        paused.set(true);
    }

    /**
     * Resumes engine work. Paused "load&display" tasks will continue its work.
     */
    void resume() {
        paused.set(false);
        synchronized (pauseLock) {
            pauseLock.notifyAll();
        }
    }

    public void stop() {
        ((ExecutorService) workExecutor).shutdownNow();
        ((ExecutorService) fileExecutor).shutdownNow();
        uriLocks.clear();
    }

    ReentrantLock getLockForUri(String uri) {
        ReentrantLock lock = uriLocks.get(uri);
        if (lock == null) {
            lock = new ReentrantLock();
            uriLocks.put(uri, lock);
        }
        return lock;
    }

    AtomicBoolean getPause() {
        return paused;
    }

    Object getPauseLock() {
        return pauseLock;
    }

    public void submit(Runnable runnable) {
        initExecutorsIfNeed();
        workExecutor.execute(runnable);
    }

    void executeFileThread(Runnable runnable) {
        initExecutorsIfNeed();
        fileExecutor.execute(runnable);
    }

}
